<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script src="./js/phaser.js"></script>
    <script>
      // 创建游戏配置对象
        let config = {
            //渲染环境 ，支持 WebGL和Canvas
            //推荐值是Phaser.AUTO，它将自动尝试使用WebGL，如果浏览器或设备不支持，它将回退为Canvas
            type: Phaser.AUTO,
            //设定了Phaser即将生成的画布元素的尺寸
            width: 800,
            height: 600,
            //引入对物理系统的支持
            physics: {
                // 有三种 Arcade, Impact, Matter.js，此处使用arcade
                default: "arcade",
                arcade: {
                    gravity: { y: 300 },
                    debug: false,
                },
            },
            //场景 预加载 创建 更新
            scene: {
                preload: preload,
                create: create,
                update: update,
            },
        };
      //一个Phaser.Game对象实例（instance）赋值给一个叫game的局部变量，
      //上述配置对象传给这个实例。这将开始启动Phaser的过程
      let game = new Phaser.Game(config);
      // 预加载  
      function preload() {
        // 加载各种图片资源 并创建唯一的资源key，在代码中生成游戏对象时将用到它
        this.load.image("sky", "assets/sky.png");
        this.load.image("star", "assets/star.png");
        this.load.image("ground", "assets/platform.png");
        this.load.image("bomb", "assets/bomb.png");
		
		// 精灵表单 由多个风格的图像组成的一组连续动作，大括号参数为一帧的宽度和高度
        this.load.spritesheet("dude", "assets/dude.png", {
          frameWidth: 32,
          frameHeight: 48,
        });
      }
	  
	  // 一堆变量定义
      let platforms;
      let cursors;
      let stars;
      let score = 0;
      let scoreText;
      let bombs;

      // 创建
      function create() {
        // 显示已经加载的一天空图像
        // 在Phaser 3 中，所有游戏对象的定位都默认基于它们的中心点
        // 此图片的大小为 800*600
        // 如果我们显示它时将它的中心定在0 x 0，你将只能看到它的右下角。
        // 如果我们显示它时定位在400 x 300，你能看到整体
        this.add.image(400, 300, "sky");

        //生成一个静态物理组，不会动
        //在Arcade物理系统中，有动态的和静态的两类物体
        //动态物体可以通过外力比如速度（velocity）、加速度（acceleration），得以四处移动。它可以跟其他对象发生反弹（bounce）、碰撞（collide），此类碰撞受物体质量和其他因素影响。
        //与此明显不同的是，静态物体只有位置和尺寸。重力对它没有影响，你不能给它设置速度，有东西跟它碰撞时，它一点都不动。名副其实，完全是静态的。所以用作地面和平台很完美，我们打算让玩家在上面来回跑动
        platforms = this.physics.add.staticGroup();

        //管道位置排列，基于中心点
		// ground的默认宽度为400 但是最下边的一条是800长度的，所以在原有基础上扩大2倍，高度为32，所以2倍为64
		// 对静态物体改变原有特征需要refreshBody
        platforms.create(400, 568, "ground").setScale(2).refreshBody();
		
		// 右下
        platforms.create(600, 400, "ground");
		// 中间悬空的靠下的
        platforms.create(390, 490, "ground");
		// 中间悬空的靠上的
        platforms.create(290, 310, "ground");
		// 左上
        platforms.create(50, 250, "ground");
		// 右上，部分被遮挡
        platforms.create(750, 220, "ground");

        //精灵的起始位置，高于最下面的管道，做一个自由落体运动
        player = this.physics.add.sprite(100, 450, "dude");
        // 设置弹跳，反射
        player.setBounce(0.2);
        //边界默认在游戏尺寸之外。把游戏（的世界边界）设置为800 x 600后，玩家就不能不跑出这个区域了
        player.setCollideWorldBounds(true);

        // 三种动画效果 左、右、转身
        this.anims.create({
          key: "left",
          frames: this.anims.generateFrameNumbers("dude", { start: 0, end: 3 }),
          frameRate: 10,
          repeat: -1,
        });
        this.anims.create({
          key: "turn",
          frames: [{ key: "dude", frame: 4 }],
          frameRate: 20,
        });
        this.anims.create({
          key: "right",
          frames: this.anims.generateFrameNumbers("dude", { start: 5, end: 8 }),
          frameRate: 10,
          repeat: -1,
        });

        // 设置人物的重力
        player.body.setGravityY(300);

        // 内置的键盘管理器
        cursors = this.input.keyboard.createCursorKeys();

		//添加星星  动态物理组
        stars = this.physics.add.group({
          key: "star",
          repeat: 11,
          setXY: { x: 12, y: 0, stepX: 70 },
        });
		// 对星星进行迭代循环
        stars.children.iterate(function (child) {
		  //赋予0.4到0.8之间的随机值，反弹范围在0（不反弹）到1之间（完全反弹）
		  // Y改变竖直方向
          child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
        });
        //检测人物和管道之间的碰撞事件
        this.physics.add.collider(player, platforms);
        //检测星星和管道之间的碰撞事件
        this.physics.add.collider(stars, platforms);
        //检测星星和人之间的重叠事件，如果检测到，他们就会被传递到'collectStar'函数
        this.physics.add.overlap(player, stars, collectStar, null, this);
        // 创建一个用于显示的文本对象，字体位置，大小和字体风格，默认值
        scoreText = this.add.text(16, 16, "score: 0", {
          fontSize: "32px",
          fill: "#000",
        });
		
		// 创建动态炸弹人组
        bombs = this.physics.add.group();
		// 设置炸弹和管道的碰撞事件
        this.physics.add.collider(bombs, platforms);
		// 设置炸弹和人物的重叠事件，如果重叠执行hitBob函数
        this.physics.add.collider(player, bombs, hitBomb, null, this);
      }
	  
	  // 收集星星
      function collectStar(player, star) {
		// 星星消失
        star.disableBody(true, true);
		// 分数叠加
        score += 10;
        scoreText.setText("Score: " + score);
		// 查看星星的个数是否为0
        if (stars.countActive(true) === 0) {
          stars.children.iterate(function (child) {
			//星星出现，并设置纵坐标为0，产生下落感觉
            child.enableBody(true, child.x, 0, true, true);
          });
		  // 判断当前任务所在位置，在对侧生成一个炸弹
          var x = player.x < 400 ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
		  // 通过炸弹组创建一个炸弹
          var bomb = bombs.create(x, 16, "bomb");
		  // 设置反弹为完全反弹,可以水平弹
          bomb.setBounce(1);
		  // 设置炸弹不能超过游戏的边界
          bomb.setCollideWorldBounds(true);
		  // 设置速度随机  velocity(速度)
          bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
        }
      }
	  // 撞到炸弹的函数
      function hitBomb(player, bomb) {
		// 物理模型停止，画面静止  
        this.physics.pause();
		// 改变人物的颜色/色调
        player.setTint(0xff0000);
		// 人物执行转身的动画
        player.anims.play("turn");
		// 游戏结束
        gameOver = true;
      }
	  // 更新，有操作时执行
      function update() {
		//左键头一直按
        if (cursors.left.isDown) {
		  // 向左移动的速度，负数代表左	
          player.setVelocityX(-160);
		  // 人物执行左的动画
          player.anims.play("left", true);
        } else if (cursors.right.isDown) {
		  // 向右移动的速度，正数代表右	
          player.setVelocityX(160);
		  // 人物执行右的动画
          player.anims.play("right", true);
        } else {
		  // 不左不右 执行转身
          player.setVelocityX(0);
          player.anims.play("turn");
        }
		// 如果是按着上，并且碰撞出现的下方，则人物会在碰撞点上升，速度越大，上升的高度越高
        if (cursors.up.isDown && player.body.touching.down) {
          player.setVelocityY(-330);
        }
      }
    </script>
  </body>
</html>
